package db;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Date;
import java.util.ArrayList;

import form.AssetForm.AssetForm;

import other.CodeDescriptionPair;


public class Asset {
	
	//Stand-alone attributes
	private int id;
	private String name;
	private String owner;
	private String custodian;
	private Date dateAcquired;
	private Date retentionPeriod;
	private String storageLocation;
	
	private CodeDescriptionPair cdpType;
	private CodeDescriptionPair cdpClassification;
	private CodeDescriptionPair cdpMaintenanceSchedule;
	private CodeDescriptionPair cdpFinancial;
	private CodeDescriptionPair cdpConfidentiality;
	private CodeDescriptionPair cdpIntegrity;
	private CodeDescriptionPair cdpAvailability;
		
	private boolean isDeleted = false;
	
	//This is private and only meant to be used by the static methods createAssetsFrom...
	private Asset(ResultSet rs){
		
		try {
				//Acquire the basic information
				id = rs.getInt("id");
				name = rs.getString("name");
				owner = rs.getString("owner");
				custodian = rs.getString("custodian");
				dateAcquired = rs.getDate("dateAcquired");
				retentionPeriod = rs.getDate("retentionPeriod");
				storageLocation = rs.getString("storageLocation");
			
				String availabilityCode = rs.getString("availability");
				String classificationCode = rs.getString("classification");
				String confidentialityCode = rs.getString("confidentiality");
				String maintenanceScheduleCode = rs.getString("maintenanceSchedule");
				String financialCode = rs.getString("financial");
				String integrityCode = rs.getString("integrity");
				String typeCode = rs.getString("type");
				
				//Initialize the descriptions 
				cdpType = new CodeDescriptionPair(typeCode, CodeDescriptionPair.TABLE_TYPE);
				cdpClassification = new CodeDescriptionPair(classificationCode, CodeDescriptionPair.TABLE_CLASSIFICATION);
				cdpMaintenanceSchedule = new CodeDescriptionPair(maintenanceScheduleCode, CodeDescriptionPair.TABLE_MINTENANCE);
				
				cdpAvailability = new CodeDescriptionPair(availabilityCode, CodeDescriptionPair.TABLE_AVAILABILITY);
				cdpConfidentiality = new CodeDescriptionPair(confidentialityCode, CodeDescriptionPair.TABLE_CONFIDENTIALITY);
				cdpFinancial = new CodeDescriptionPair(financialCode, CodeDescriptionPair.TABLE_FINANCIAL);
				cdpIntegrity = new CodeDescriptionPair(integrityCode, CodeDescriptionPair.TABLE_INTEGRITY);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/*Static Methods*/
	
	//This is so we won't have to keep recoding the query and creation of asset objects if we wish to only have one.
	public static Asset createAssetFromID(int id){
		String query = "SELECT * FROM Asset WHERE id = "+id+";";
		return createAsset(query);
	}
	
	public static Asset createAssetFromIDTableDateTime(int ID, String tableName, String dateTime)
	{
		String query;
		if(tableName.toLowerCase().equals("deletelog"))
			query = "SELECT * FROM Asset WHERE ID = "+ID+";";
		else
			query = "SELECT * FROM "+tableName+" WHERE ID = "+ID+" AND dateTime = \""+dateTime+"\";";
	
		return createAsset(query);
	}
	
	private static Asset createAsset(String query){
		Connection con = DBConnectionFactory.getInstance().getConnection();
		ResultSet rs = DBConnector.executeQuery(con, query);
		
		Asset newAsset = null;		
		
		try {
			if(rs != null && rs.next())
			{
				newAsset = new Asset(rs);
			}
		} catch (SQLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	
		try {
			con.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return newAsset;
	}
	
	public static String retrieveAssetName(int ID){
		String query = "Select Name from Asset where ID = "+ID+";";
		Connection con = DBConnectionFactory.getInstance().getConnection();
		String name = DBConnector.executeQueryWithSingleValue(con, query);
		try {
			con.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return name;
	}
	
	//This will be used to insert a new asset into the database. Returns true if successful.	
	public static boolean insertNewAssetIntoDB(AssetForm addAssetForm)
	{
		Connection con = DBConnectionFactory.getInstance().getConnection();
		String idQuery = "SELECT LAST_INSERT_ID()";
		String query;
		int id = -1;
		
		String name = addAssetForm.getAssetName().getInput();
		String owner = addAssetForm.getOwner().getInput();
		String custodian = addAssetForm.getCustodian().getInput();
		String storageLocation = addAssetForm.getCustodian().getInput();
		
		Date dateAcquired = Date.valueOf(addAssetForm.getDateAcquired().getInput());
		Date retentionPeriod = Date.valueOf(addAssetForm.getRetentionPeriod().getInput());
		
		//get code from input in fields
		String classificationCode = CodeDescriptionPair.getCode(CodeDescriptionPair.TABLE_CLASSIFICATION, addAssetForm.getClassification().getInput());
		String typeCode = CodeDescriptionPair.getCode(CodeDescriptionPair.TABLE_TYPE, addAssetForm.getType().getInput());
		String maintenanceScheduleCode = CodeDescriptionPair.getCode(CodeDescriptionPair.TABLE_MINTENANCE, addAssetForm.getMaintenanceSched().getInput());
		String financialCode = CodeDescriptionPair.getCode(CodeDescriptionPair.TABLE_FINANCIAL, addAssetForm.getFinancialVal().getInput());
		String confidentialityCode = CodeDescriptionPair.getCode(CodeDescriptionPair.TABLE_CONFIDENTIALITY, addAssetForm.getConfidentialityVal().getInput());
		String integrityCode = CodeDescriptionPair.getCode(CodeDescriptionPair.TABLE_INTEGRITY, addAssetForm.getIntegrityVal().getInput());
		String availabilityCode = CodeDescriptionPair.getCode(CodeDescriptionPair.TABLE_AVAILABILITY, addAssetForm.getAvailabilityVal().getInput());
		
		try {
			query = "INSERT into Asset(name, owner, custodian, type, dateAcquired, retentionPeriod, maintenanceSchedule, financial, confidentiality, integrity, availability, classification, storageLocation, isDeleted)" +
					"values(\""+name+"\", \""+owner+"\", \""+custodian+"\", \""+typeCode+"\", \""+dateAcquired+"\", \""+retentionPeriod+"\", \""+maintenanceScheduleCode+"\", \""+financialCode+"\", \""+confidentialityCode+"\", \""+integrityCode+"\", \""+availabilityCode+"\", \""+classificationCode+"\", \""+storageLocation+"\", 0)";
			
			DBConnector.executeUpdate(con, query);
			id = Integer.parseInt(DBConnector.executeQueryWithSingleValue(con, idQuery));
			
			Asset asset = Asset.createAssetFromID(id);
			LogMethods log = new LogMethods();
			log.AddLog(asset);
			
			con.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if(id == -1)
			return false;
		
		return true;
	}
		
	private String generateUpdateQuery(Asset a) {
		ArrayList<String> storage = new ArrayList<String>();
		String que = "UPDATE Asset SET ";
		
		if(!name.equals(a.getName())) 
			storage.add("name = \""+a.getName()+"\"");
		
		if(!owner.equals(a.getOwner())) 
			storage.add("owner = \""+a.getOwner()+"\"");
		
		if(!custodian.equals(a.getCustodian())) 
			storage.add("custodian = \""+a.getCustodian()+"\"");
		
		if(!storageLocation.equals(a.getStorageLocation()))
			storage.add("storageLocation = \""+a.getStorageLocation()+"\"");
		
		if(!dateAcquired.equals(a.getDateAcquired()))
			storage.add("dateAcquired =  \""+a.getDateAcquired()+"\"");
		
		if(!retentionPeriod.equals(a.getRetentionPeriod()))
			storage.add("retentionPeriod = \""+a.getRetentionPeriod()+"\"");
		
		if(!getTypeCode().equals(a.getTypeCode()))
			storage.add("Type = \""+a.getTypeCode()+"\"");
		
		if(!getClassificationCode().equals(a.getClassificationCode()))
			storage.add("Classification = \""+a.getClassificationCode()+"\"");
		
		if(!getMaintenanceScheduleCode().equals(a.getMaintenanceScheduleCode()))
			storage.add("maintenanceSchedule = \""+a.getMaintenanceScheduleCode()+"\"");
		
		if(!getAvailabilityCode().equals(a.getAvailabilityCode()))
			storage.add("availability = \""+a.getAvailabilityCode()+"\"");
		
		if(!getFinancialCode().equals(a.getFinancialCode()))
			storage.add("financial = \""+a.getFinancialCode()+"\"");
		
		if(!getIntegrityCode().equals(a.getIntegrityCode()))
			storage.add("integrity = \""+a.getIntegrityCode()+"\"");
		
		if(!getConfidentialityCode().equals(a.getConfidentialityCode()))
			storage.add("confidentiality = \""+a.getConfidentialityCode()+"\"");

		for(int r = 0; r<storage.size(); r++){
			que += storage.get(r);
			if(r != storage.size() - 1)
				que += ", ";
		}
		
		que += " WHERE id = "+a.getId()+"";
		return que;
	}
	
	@Override public boolean equals(Object o)
	{
		Asset other = (Asset) o;
		
		if(!name.equals(other.getName()))
			return false;
	
		if(!owner.equals(other.getOwner())) 
			return false;
			
		if(!custodian.equals(other.getCustodian())) 
			return false;

		if(!storageLocation.equals(other.getStorageLocation()))
			return false;
		
		if(!dateAcquired.equals(other.getDateAcquired()))
			return false;
		
		if(!retentionPeriod.equals(other.getRetentionPeriod()))
			return false;
		
		if(!getTypeCode().equals(other.getTypeCode()))
			return false;
		
		if(!getClassificationCode().equals(other.getClassificationCode()))
			return false;
		
		if(!getMaintenanceScheduleCode().equals(other.getMaintenanceScheduleCode()))
			return false;
		
		if(!getAvailabilityCode().equals(other.getAvailabilityCode()))
			return false;
		
		if(!getFinancialCode().equals(other.getFinancialCode()))
			return false;
		
		if(!getIntegrityCode().equals(other.getIntegrityCode()))
			return false;
		
		if(!getConfidentialityCode().equals(other.getConfidentialityCode()))
			return false;
		
		return true;
	}
	
	public Asset getCopy()
	{
		Asset copy = createAssetFromID(id);
		
		copy.setName(name);
		copy.setOwner(owner);
		copy.setCustodian(custodian);
		copy.setStorageLocation(storageLocation);
		
		copy.setDateAcquired(dateAcquired);
		copy.setRetentionPeriod(retentionPeriod);
		
		copy.setTypeCode(getTypeCode());
		copy.setClassificationCode(getClassificationCode());
		copy.setMaintenanceScheduleCode(getMaintenanceScheduleCode());
		copy.setAvailabilityCode(getAvailabilityCode());
		copy.setFinancialCode(getFinancialCode());
		copy.setIntegrityCode(getIntegrityCode());
		copy.setAvailabilityCode(getAvailabilityCode());
		
		return copy;
	}
	
	public void updateSelfInDB(Asset editedVersion)
	{
		if(!this.equals(editedVersion)){
			String query = generateUpdateQuery(editedVersion);
			Connection con = DBConnectionFactory.getInstance().getConnection();	
			DBConnector.executeUpdate(con, query);
			
			LogMethods log = new LogMethods();
			log.EditLog(editedVersion);
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}	
		}
	}
	
	public void deleteSelfInDB()
	{
		Connection con = DBConnectionFactory.getInstance().getConnection();
		String query = "UPDATE Asset set isDeleted = 1 WHERE id = "+id+";";
		DBConnector.executeUpdate(con, query);
		
		LogMethods log = new LogMethods();
		log.DeleteLog(this);
		
		try {
			con.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}
	
	/* Auto-Generated Getters and Setters*/

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getOwner() {
		return owner;
	}

	public void setOwner(String owner) {
		this.owner = owner;
	}

	public String getCustodian() {
		return custodian;
	}

	public void setCustodian(String custodian) {
		this.custodian = custodian;
	}

	public Date getDateAcquired() {
		return dateAcquired;
	}

	public void setDateAcquired(Date dateAcquired) {
		this.dateAcquired = dateAcquired;
	}

	public Date getRetentionPeriod() {
		return retentionPeriod;
	}

	public void setRetentionPeriod(Date retentionPeriod) {
		this.retentionPeriod = retentionPeriod;
	}

	public String getStorageLocation() {
		return storageLocation;
	}

	public void setStorageLocation(String storageLocation) {
		this.storageLocation = storageLocation;
	}

	public String getAvailabilityCode() {
		return cdpAvailability.getCode();
	}

	public void setAvailabilityCode(String availabilityCode) {
		cdpAvailability.setCode(availabilityCode);
	}

	public String getClassificationCode() {
		return cdpClassification.getCode();
	}

	public void setClassificationCode(String classificationCode) {
		cdpClassification.setCode(classificationCode);
	}

	public String getConfidentialityCode() {
		return cdpConfidentiality.getCode();
	}

	public void setConfidentialityCode(String confidentialityCode) {
		cdpConfidentiality.setCode(confidentialityCode);
	}

	public String getMaintenanceScheduleCode() {
		return cdpMaintenanceSchedule.getCode();
	}

	public void setMaintenanceScheduleCode(String maintenanceScheduleCode) {
		cdpMaintenanceSchedule.setCode(maintenanceScheduleCode);
	}

	public String getFinancialCode() {
		return cdpFinancial.getCode();
	}

	public void setFinancialCode(String financialCode) {
		cdpFinancial.setCode(financialCode);
	}

	public String getIntegrityCode() {
		return cdpIntegrity.getCode();
	}

	public void setIntegrityCode(String integrityCode) {
		cdpIntegrity.setCode(integrityCode);
	}

	public String getTypeCode() {
		return cdpType.getCode();
	}

	public void setTypeCode(String typeCode) {
		cdpType.setCode(typeCode);
	}

	public int getId() {
		return id;
	}

	public String getAvailabilityDesc() {
		return cdpAvailability.getDescription();
	}

	public String getClassificationDesc() {
		return cdpClassification.getDescription();
	}

	public String getConfidentialityDesc() {
		return cdpConfidentiality.getDescription();
	}

	public String getMaintenanceScheduleDesc() {
		return cdpMaintenanceSchedule.getDescription();
	}

	public String getFinancialDesc() {
		return cdpFinancial.getDescription();
	}

	public String getIntegrityDesc() {
		return cdpIntegrity.getDescription();
	}

	public String getTypeDesc() {
		return cdpType.getDescription();
	}
}
